﻿using System.Threading;
using System.Windows;
using DryIoc;
using DryIoc.Microsoft.DependencyInjection;
using MeterReader.Common.Config;
using MeterReader.Models;
using MeterReader.Services;
using MeterReader.Services.Repositories;
using MeterReader.Views;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using NLog.Extensions.Logging;
using Prism.DryIoc;
using Prism.Ioc;

namespace MeterReader
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : PrismApplication
    {
        private static Mutex _mutex;

        /// <summary>
        /// 防止重复启动
        /// </summary>
        /// <param name="e"></param>
        protected override void OnStartup(StartupEventArgs e)
        {
            _mutex = new Mutex(true, "OnlyRun_CRNS");
            // 防止多次启动
            if (_mutex.WaitOne(0, false))
            {
                base.OnStartup(e);
                // 创建数据库
                using (var scope = Container.CreateScope())
                {
                    var context = scope.Resolve<MeterDBContext>();
                    context.Database.EnsureCreated();
                }
            }
            else
            {
                MessageBox.Show("程序已在运行中！", "重复打开提示");
                Shutdown();
            }
        }

        /// <summary>
        /// 启动画面
        /// </summary>
        /// <returns></returns>
        protected override Window CreateShell() => Container.Resolve<MainWindow>();

        /// <summary>
        /// 依赖注册
        /// </summary>
        /// <param name="containerRegistry"></param>
        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry
                .RegisterSingleton<IReadRepository, MeterReadRepository>()
                .RegisterSingleton<IWriteDbRepository, MeterWriteRepository>()
                .RegisterSingleton<IDataService, SimDBReadService>();
            containerRegistry.RegisterForNavigation<MetersDataMonitor>();
            containerRegistry.RegisterForNavigation<MetersCurve>();
            containerRegistry.RegisterForNavigation<History>();
        }

        /// <summary>
        /// 使用在DryIoC中使用MS.DI容器的接口
        /// </summary>
        /// <returns></returns>
        protected override IContainerExtension CreateContainerExtension()
        {
            IServiceCollection services = new ServiceCollection();
            ConfigMSDI(services);
            var container = new Container(CreateContainerRules());
            container.WithDependencyInjectionAdapter(services);
            return new DryIocContainerExtension(container);
        }

        /// <summary>
        /// 重写容器规则，删除新版本弃用的 WithoutFastExpressionCompiler 方法
        /// </summary>
        /// <returns></returns>
        protected override Rules CreateContainerRules()
        {
            return Rules
                .Default.WithConcreteTypeDynamicRegistrations(reuse: Reuse.Transient)
                .With(Made.Of(FactoryMethod.ConstructorWithResolvableArguments))
                .WithFuncAndLazyWithoutRegistration()
                .WithTrackingDisposableTransients()
                .WithFactorySelector(Rules.SelectLastRegisteredFactory());
        }

        /// <summary>
        /// 配置MS.DI容器,只是为了使用MS的配置、EFCore的扩展方法
        /// </summary>
        /// <param name="serviceDescriptors"></param>
        private void ConfigMSDI(IServiceCollection serviceDescriptors)
        {
            var config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build().Get<Config>();
            GlobalSettings.MaxMaxSeriesPonts = config!.MaxSeriesPonts;
            serviceDescriptors
                .AddLogging((builder) => builder.AddNLog())
                .AddDbContext<SimMeterDBContext>((s, options) => options.UseSqlite(config.FromConnectionString))
                .AddDbContext<MeterDBContext>((s, options) => options.UseSqlite(config.ToConnectionString));
        }
    }
}
